#!/usr/bin/env python
# -*- coding:utf-8 -*-

import threading
from socketserver import ThreadingTCPServer,BaseRequestHandler
import sys,logging

# SocketServer
# 测试代码
"""
import threading,socketserver

class MyHandler(socketserver.BaseRequestHandler):
    def handle(self):
        # super().handle() # 可以不调用,父类handle什么都没有做.
        print('-'*30)
        print(self.server) # 服务
        print(self.request) # 服务端负责客户端连接请求的socket对象.
        print(self.client_address) # 客户端地址.
        print(self.__dict__)
        print(self.server.__dict__) # 能看到负责accept的socket

        print(threading.enumerate())
        print(threading.current_thread())
        print('-'*30)


addr = ('127.0.0.1',9999)
server = socketserver.ThreadingTCPServer(addr,MyHandler)

server.serve_forever() # 永久.
"""
"""
测试结果说明,handle方法相当于socket的recv方法.
每个不同的连接上的请求过来后,生成这个连接的socket对象即self.request,
客户端地址是self.client_address.
"""


"""
问题：
    测试过程中,上面代码,连接后立即断开了,为什么?
    怎样才能客户端和服务器端长时间连接?
"""
"""
import threading,socketserver,logging

FORMAT = "%(asctime)s %(threadName)s %(thread)d %(message)s"
logging.basicConfig(format=FORMAT,level=logging.INFO)

class MyHandler(socketserver.BaseRequestHandler):
    def handle(self):
        # super().handle() # 可以不调用,父类handle什么都没有做.
        print('-'*30)
        print(self.server) # 服务
        pirnt(self.request) # 服务端负责客户端连接请求的socket对象.
        print(self.client_address) # 客户端地址.
        print(self.__dict__)
        print(self.server.__dict__) # 能看到负责accept的.

        print(threading.enumerate())
        print(threading.current_thread())

        print('-'*30)
        for i in range(3):
            data = self.request.recv(1024)
            logging.info(data)
        logging.info('=========end==========')


addr = ('127.0.0.1',9999)
server = socketserver.ThreadingTCPServer(addr,MyHandler)
server.serve_forever() # 永久
"""
"""
将ThreadingTCPServer换成TCPServer,同时连接2个客户端观察效果.
ThreadingTCPServer是异步的,可以同时处理多个连接.
TCPServer是同步的,一个连接处理完了,即一个连接的handle方法执行完了,才能处理另一个连接,且只有主线程.
"""



# 实现EchoServer
# Echo,来什么消息回显什么消息. 客户端发来什么信息,返回什么信息.
"""
import threading
from socketserver import ThreadingTCPServer,BaseRequestHandler
import sys

class EchoHandler(BaseRequestHandler):
    def setup(self):
        super().setup()
        self.event = threading.Event() # 初始工作.

    def finish(self):
        super().finish()
        self.event.set()

    def handle(self):
        super().handle()

        while not self.event.is_set():
            data = self.request.recv(1024).decode()
            msg = "{} {}".format(self.client_address,data).encode()
            self.request.send(msg)
        print('End')


addr = ('127.0.0.1',9999)
server = ThreadingTCPServer(addr,EchoHandler)

server_thread = threading.Thread(target=server.serve_forever,name='EchoServer',daemon=True)
server_thread.start()

try:
    while True:
        cmd = input('>>>')
        if cmd.strip() == 'quit':
            break
        print(threading.enumerate())
except Exception as e:
    print(e)
except KeyboardInterrupt:
    pass
finally:
    print('Exit')
    sys.exit(0)
"""







# 练习----改写ChatServer:
# 使用ThreadingTCPServer改写ChatServer
"""
import threading
from socketserver import ThreadingTCPServer,BaseRequestHandler
import sys,logging

FORMAT = "%(asctime)s %(threadName)s %(thread)d %(message)s"
logging.basicConfig(format=FORMAT,level=logging.INFO)

class ChatHandler(BaseRequestHandler):
    clients = {}

    def setup(self):
        super().setup()
        self.event = threading.Event() # 初始工作.
        self.clients[self.client_address] = self.request

    def finish(self):
        super().finish() # 清理工作.
        self.clients.pop(self.client_address) # 能执行到吗?
        self.event.set()

    def handle(self):
        super().handle()
        while not self.event.is_set():
            data = self.request.recv(1024).decode()
            if data == 'quit':
                break
            msg = "{} {}".format(self.client_address,data).encode()
            logging.info(msg)
            for c in self.clients.values():
                self.request.send(msg)
        print('End')


addr = ('127.0.0.1',9999)
server = ThreadingTCPServer(addr,ChatHandler)

server_thread = threading.Thread(target=server.serve_forever,name='ChatServer',daemon=True)
server_thread.start()

try:
    while True:
        cmd = input('>>>')
        if cmd.strip() == 'quit':
            break
        print(threading.enumerate())
except Exception as e:
    print(e)
except KeyboardInterrupt:
    pass
finally:
    print('Exit')
    sys.exit(0)
"""
"""
问题:
   上例self.clients.pop(self.client_address) 能执行到嘛?
   如果连接的线程中handle方法中抛出异常,例如客户端主动断开导致的异常,线程崩溃,self.clients的pop方法还能执行嘛?
   当然能执行,基类源码保证了即使异常,也能执行finish方法。但不代表不应该不捕获客户端各种异常.
"""








# 解决客户端主动连接断开问题
# 如果客户端主动断开,总是抛开一个异常,看看到底发生了什么,在handle方法中增加一些语句.
"""
class ChatHandler(BaseRequestHandler):
    clients = {}

    def setup(self):
        super().setup()
        self.event = threading.Event() # 初始工作.
        self.clients[self.client_address] = self.request

    def finish(self):
        super().finish() # 清理工作.
        self.clients.pop(self.client_address) # 能执行到吗
        self.event.set()

    def handle(self):
        super().handle()

        while not self.event.is_set():
            data = self.request.recv(1024).decode()
            print(data,'~'*20) # 增加
            if data == 'quit':
                break
            msg = "{} {}".format(self.client_address,data).encode()
            logging.info(msg)
            for c in self.clients.values():
                print('+'*20) # 增加
                self.request.send(msg)

        print('End')
"""
"""
通过打印可以看到,客户端主动断开,会导致recv方法立即返回一个空bytes,并没有同时抛出异常.
当循环回到recv这一句的时候就会抛出异常. 所以,可以通过判断data数据是否为空来客户端是否断开.
"""





"""
class ChatHandler(BaseRequestHandler):
    clients = {}

    def setup(self):
        super().setup()
        self.event = threading.Event() # 初始工作.
        self.clients[self.client_address] = self.request

    def finish(self):
        super().finish() # 清理工作.
        self.clients.pop(self.client_address) # 能执行到嘛?
        self.event.set()

    def handle(self):
        super().handle()

        while not self.event.is_set():
            data = self.request.recv(1024).decode()
            print(data, '~'*20)
            if not data or data == 'quit':
                print('Broken pipe')
                break
            msg = "{} {}".format(self.client_address,data).encode()
            logging.info(msg)
            for c in self.clients.values():
                self.request.send(msg)

        print('End')
"""
"""
总结:
    为每一个连接提供RequestHandlerClass类实例,依次调用setup,handle,finish方法,
    且使用了try...finally结构
    保证finish方法一定能被调用. 这些方法依次执行完成,如果想维持这个连接和客户端通信,
    就需要在handle函数中使用循环.
    socketserver模块提供的不同的类,但是编程接口是一样的,即使是多进程,多线程的类也是一样,
    大大减少了编程的难度.
"""
